/**
 * C Implementation: grib_index
 *
 * Description: 
 * How to create and use an index to access GRIB messages from a file
 * 如何创建和使用索引从文件访问 GRIB 消息
 * 
 */

#include "eccodes.h"

int sfx_grib_index()
{
    int ret      = 0;
    char* infile = "d:\\temp\\era5-levels-members.grib";

    // ----------------------------------------------------
    printf("begin indexing...\n");

    //  Create an index given set of keys (cannot have spaces)
    codes_index* index = codes_index_new(0, "shortName,level,number,step", &ret);
    printf("codes_index_new(...) - %s\n", codes_get_error_message(ret));

    // Indexes a file
    ret = codes_index_add_file(index, infile);
    printf("codes_index_add_file(...) - %s\n", codes_get_error_message(ret));

    printf("end indexing...\n");
    // ----------------------------------------------------
    // steps: get the number of distinct values of "step" in the index (获取索引中“step”的不同值的数量)
    size_t stepSize = 0;
    CODES_CHECK(codes_index_get_size(index, "step", &stepSize), 0);
    long* steps = (long*)malloc(sizeof(long) * stepSize);
    // get the list of distinct steps from the index.the list is in ascending order
    CODES_CHECK(codes_index_get_long(index, "step", steps, &stepSize), 0);
    printf("stepSize = %ld\n", (long)stepSize);
    for (int i = 0; i < stepSize; i++) {
        printf("%ld ", steps[i]);
    }
    printf("\n");

    // levels: same as for "step"
    size_t levelSize = 0;
    CODES_CHECK(codes_index_get_size(index, "level", &levelSize), 0);
    long* levels = (long*)malloc(sizeof(long) * levelSize);
    CODES_CHECK(codes_index_get_long(index, "level", levels, &levelSize), 0);
    printf("levelSize = %ld\n", (long)levelSize);
    for (int i = 0; i < levelSize; i++) {
        printf("%ld ", levels[i]);
    }
    printf("\n");

    // numbers: same as for "step"
    size_t numberSize = 0;
    CODES_CHECK(codes_index_get_size(index, "number", &numberSize), 0);
    long* numbers = (long*)malloc(sizeof(long) * numberSize);
    CODES_CHECK(codes_index_get_long(index, "number", numbers, &numberSize), 0);
    printf("numberSize = %ld\n", (long)numberSize);
    for (int i = 0; i < numberSize; i++) {
        printf("%ld ", numbers[i]);
    }
    printf("\n");

    // shortName: same as for "step"
    size_t shortNameSize = 0;
    CODES_CHECK(codes_index_get_size(index, "shortName", &shortNameSize), 0);
    char** shortName = (char**)malloc(shortNameSize * sizeof(char*));
    CODES_CHECK(codes_index_get_string(index, "shortName", shortName, &shortNameSize), 0);
    printf("shortNameSize = %ld\n", (long)shortNameSize);
    for (int i = 0; i < shortNameSize; i++) {
        printf("%s ", shortName[i]);
    }
    printf("\n");

    int count = 0;
    long ostep, olevel, onumber;
    char oshortName[200];
    size_t lenshortName = 200;
    codes_handle* h     = NULL;
    // nested loops on the keys values of the index (索引键值上的嵌套循环)
    // different order of the nested loops doesn't affect performance (嵌套循环的不同顺序不会影响性能)
    for (int i = 0; i < shortNameSize; i++) {
        //
        // select the GRIB with shortName = shortName[i]
        codes_index_select_string(index, "shortName", shortName[i]);
        for (int l = 0; l < levelSize; l++) {
            // select the GRIB with level = levels[l]
            codes_index_select_long(index, "level", levels[l]);
            for (int j = 0; j < numberSize; j++) {
                // select the GRIB with number = numbers[j]
                codes_index_select_long(index, "number", numbers[j]);
                for (int k = 0; k < stepSize; k++) {
                    // select the GRIB with step = steps[k]
                    codes_index_select_long(index, "step", steps[k]);
                    // create a new codes_handle from the index with the constraints
                    // imposed by the select statements. It is a loop because
                    // in the index there could be more than one GRIB with those
                    // constraints
                    while ((h = codes_handle_new_from_index(index, &ret)) != NULL) {
                        //
                        count++;

                        codes_get_string(h, "shortName", oshortName, &lenshortName);
                        codes_get_long(h, "level", &olevel);
                        codes_get_long(h, "number", &onumber);
                        codes_get_long(h, "step", &ostep);
                        printf("shortName=%s ", oshortName);
                        printf("level=%ld ", olevel);
                        printf("number=%ld ", onumber);
                        printf("step=%ld \n", ostep);

                        if (ret) {
                            fprintf(stderr, "Error: %s\n", codes_get_error_message(ret));
                            codes_handle_delete(h);
                            break;
                        }

                        codes_handle_delete(h);
                    }  // while
                    if (ret && ret != GRIB_END_OF_INDEX) {
                        fprintf(stderr, "Error: %s\n", codes_get_error_message(ret));
                        break;
                    }
                }  // k
            }      // j
        }          // l
    }              // i
    printf("  %d messages selected\n", count);
    codes_index_write(index, "d:/temp/out.gribidx");    // 写入GRIB索引文件

    // free memory
    for (int i = 0; i < shortNameSize; i++) {
        free(shortName[i]);
    }
    free(shortName);
    free(numbers);
    free(levels);
    free(steps);

    codes_index_delete(index);
    return 0;
}
